using System;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.PackageManager;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

namespace Editor.Scripts
{
    [AddComponentMenu("Custom Clouds/Clouds Resource Generator")]
    public class CloudsResourceGenerator : MonoBehaviour
    {
        [HideInInspector] public string cloudsFolder = "Assets/Resources/Clouds";
        [HideInInspector] public string noiseFolder = "";
        [HideInInspector] public bool texToResFld = true;
        [HideInInspector] public bool texSaveIndividual = true;

        // 遍历生成Index与Data贴图
        public void GenerateClouds()
        {
            var cloudsPath = (cloudsFolder.EndsWith("/") ? cloudsFolder : cloudsFolder + "/");
            if (!Directory.Exists(cloudsPath)) Directory.CreateDirectory(cloudsPath);
            foreach (var directory in new DirectoryInfo(cloudsPath).GetDirectories())
            {
                CreateTexturePerCloud(cloudsPath, directory.Name); // 获取到目录下的每一个子目录，在子目录下创建3D纹理
            }
        }

        // 清空体积云数据
        public void ClearCloudsGeneration()
        {
            var cloudsPath = (cloudsFolder.EndsWith("/") ? cloudsFolder : cloudsFolder + "/");
            foreach (var directory in new DirectoryInfo(cloudsPath).GetDirectories())
            {
                var texParentPath = texSaveIndividual ? Path.Combine(cloudsPath, directory.Name) : cloudsPath;
                var texParentDir = new DirectoryInfo(texParentPath);
                foreach (var file in texParentDir.GetFiles(texSaveIndividual ? "*" + texParentDir.Name + "*" : "*" + directory.Name + "*"))
                {
                    AssetDatabase.DeleteAsset(Path.Combine(texParentPath, file.Name));
                }
            }
        }

        // 生成NOise贴图
        public void GenerateNoise()
        {
            T2D noise;
            noise.format = TextureFormat.R8;
            noise.name = "noise";
            noise.wrapMode = TextureWrapMode.Repeat;
            noise.filterMode = FilterMode.Bilinear;
            Create3DTexture(noise, noiseFolder, "");
        }

        // 生成Volume数据
        public void ApplyVolume()
        {
            var volume = FindObjectOfType<Volume>();
            var scenePath = SceneManager.GetActiveScene().path;
            var sceneFolder = scenePath[..^6];
            const string tempProfile = "Packages/com.mrop.rendering-adventure.sky-volumetric-clouds/Resources/Volume/Temp.asset";
            const string templateProfile = "Packages/com.mrop.rendering-adventure.sky-volumetric-clouds/Resources/Volume/CastleVolume.asset";
            
            if (volume == null) //如果场景没加Volume，创建Volume GameObject，拷贝预设volume profile
            {
                if (!Directory.Exists(sceneFolder)) Directory.CreateDirectory(sceneFolder);
                var resPath = Path.Combine(sceneFolder, "generatedProfile.asset");
                AssetDatabase.CopyAsset(templateProfile, resPath);
                var volumeProfile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(resPath);

                var volumeObj = new GameObject();
                volumeObj.AddComponent<Volume>();
                volumeObj.name = "Volume";
                volumeObj.GetComponent<Volume>().sharedProfile = volumeProfile;
            }
            else
            {
                AssetDatabase.CopyAsset(templateProfile, tempProfile);
                var presetVolumeProfile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(tempProfile);
                var presetCloudsVolume = presetVolumeProfile.components.Find(component => component.GetType() == typeof(HoudiniCloudsVolume));

                var profile = volume.sharedProfile;
                if (profile == null) // 如果只有Volume没有Profile，拷贝预设volume profile并赋值
                {

                    if (!Directory.Exists(sceneFolder)) Directory.CreateDirectory(sceneFolder);
                    var resPath = Path.Combine(sceneFolder, "generatedProfile.asset");
                    AssetDatabase.CopyAsset(templateProfile, resPath);
                    volume.sharedProfile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(resPath);
                }
                else // 如果存在Profile
                {
                    profile.TryGet(out HoudiniCloudsVolume cloudsVolume);
                    if (cloudsVolume != null) return; // 如果profile里面存在HoudiniCloudsVolume，直接返回不做改变，不然的话在原来资源的基础上把预设的HoudiniCloudsVolume复制过来

                    profile.Add<HoudiniCloudsVolume>();
                    for (var i = 0; i < profile.components.Count; i++) // 使用样例Volume中的HouidniCloudsVolume预设替换临时生成的Volume
                    {
                        if (profile.components[i].name != "HoudiniCloudsVolume") continue;
                        profile.components[i] = presetCloudsVolume;
                        break;
                    }

                    volume.sharedProfile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(AssetDatabase.GetAssetPath(volume.sharedProfile));
                    AssetDatabase.SaveAssets();
                }
            }
        }

        private void CreateTexturePerCloud(string cloudsPath, string cloudName)
        {
            T2D index, data, w, r, b;
            index.format = TextureFormat.RGB24;
            index.name = "index";
            index.wrapMode = TextureWrapMode.Clamp;
            index.filterMode = FilterMode.Point;
            Create3DTexture(index, cloudsPath, cloudName);

            data.format = TextureFormat.R8;
            data.name = "data";
            data.wrapMode = TextureWrapMode.Clamp;
            data.filterMode = FilterMode.Bilinear;
            Create3DTexture(data, cloudsPath, cloudName);

            r.format = TextureFormat.R8;
            r.name = "r";
            r.wrapMode = TextureWrapMode.Clamp;
            r.filterMode = FilterMode.Bilinear;
            Create3DTexture(r, cloudsPath, cloudName);

            b.format = TextureFormat.RGBA32;
            b.name = "b";
            b.wrapMode = TextureWrapMode.Clamp;
            b.filterMode = FilterMode.Bilinear;
            Create3DTexture(b, cloudsPath, cloudName);

            w.format = TextureFormat.RGBA32;
            w.name = "w";
            w.wrapMode = TextureWrapMode.Clamp;
            w.filterMode = FilterMode.Bilinear;
            Create3DTexture(w, cloudsPath, cloudName);
        }

        /// <summary>
        /// 使用传入的T2D结构体创建3D纹理
        /// </summary>
        /// <param name="t">传入要从要转换为三维数组的T2D结构体</param>
        /// <param name="texture2DFolder">Assets/Resources/Clouds等</param>
        /// <param name="texture2DName">3D资源属性名字，index, data等</param>
        private void Create3DTexture(T2D t, string texture2DFolder, string texture2DName)
        {
            var texFolderPath = Path.Combine(texture2DFolder, texture2DName, t.name);
            var texPath = texSaveIndividual
                ? Path.Combine(texture2DFolder, texture2DName, t.name + "_" + texture2DName + ".asset")
                : Path.Combine(texture2DFolder, t.name + "_" + texture2DName + ".asset");
            if (!Directory.Exists(texFolderPath))
            {
                Debug.Log("路径不存在：" + texFolderPath);
                return;
            }

            if (File.Exists(texPath))
            {
                Debug.Log("目标生成文件已存在：" + texPath);
                return;
            }

            // 读取图片的Texture2D
            var img0 = new Texture2D(2, 2);
            var texFolder = new DirectoryInfo(texFolderPath);
            img0.LoadImage(File.ReadAllBytes(Path.Combine(texFolderPath, texFolder.GetFiles(t.name + "0*")[0].Name)));
            var depth = new DirectoryInfo(texFolderPath).GetFiles().Length / 2; // 取文件总数的一半，还有一半是meta文件
            var width = img0.width;
            var height = img0.height;

            // 创建纹理并应用配置
            var texture = new Texture3D(width, height, depth, t.format, false)
            {
                wrapMode = t.wrapMode,
                filterMode = t.filterMode
            };

            // 创建 3 维数组以存储颜色数据
            var colors = new Color[width * height * depth];

            // 填充数组，使纹理的 x、y 和 z 值映射为红色、蓝色和绿色
            for (var i = 0; i < depth; i++)
            {
                img0.LoadImage(File.ReadAllBytes(Path.Combine(texFolderPath, texFolder.GetFiles(t.name + i + "*")[0].Name)));
                var texColors = img0.GetPixels(); // colors
                texColors.CopyTo(colors, width * height * i);
            }

            texture.SetPixels(colors); // 将颜色值复制到纹理
            texture.Apply(); // 将更改应用到纹理，然后将更新的纹理上传到 GPU
            AssetDatabase.CreateAsset(texture, texPath);
            Debug.Log("生成：" + texture2DName + "-" + t.name);
        }

        private struct T2D
        {
            public TextureFormat format;
            public string name;
            public TextureWrapMode wrapMode;
            public FilterMode filterMode;
        }
    }
}